package com.winit.schedule.job.tracker.repository.mongo;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.winit.schedule.core.repository.entity.*;
import com.winit.schedule.core.repository.query.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.winit.schedule.core.conf.Configuration;
import com.winit.schedule.core.model.JobID;
import com.winit.schedule.core.repository.JobRepository;
import com.winit.schedule.core.repository.RepositoryEngine;
import com.winit.schedule.core.repository.TaskItemRepository;
import com.winit.schedule.core.repository.TaskRepository;
import com.winit.schedule.core.repository.TaskTrackerRepository;
import com.winit.schedule.core.repository.constants.JobStatus;
import com.winit.schedule.core.repository.constants.LogType;
import com.winit.schedule.core.repository.constants.TaskStatus;
import com.winit.schedule.core.utils.Clock;
import com.winit.schedule.core.utils.DateUtils;
import com.winit.schedule.core.utils.StringUtils;
import com.winit.schedule.job.tracker.repository.ConsoleDataManager;

public class MongoConsoleDataManager extends MongoLogDataManager implements ConsoleDataManager {

    private static transient final Logger logger = LoggerFactory.getLogger(MongoScheduleDataManager.class);

    private RepositoryEngine              repositoryEngine;

    private TaskTrackerRepository         taskTrackerRepository;

    private TaskRepository                taskRepository;

    private TaskItemRepository            taskItemRepository;

    private JobRepository                 jobRepository;

    public MongoConsoleDataManager(Configuration conf){
        repositoryEngine = new MongoRepositoryImpl(conf);
        taskTrackerRepository = repositoryEngine.getTaskTrackerRepository();
        taskRepository = repositoryEngine.getTaskRepository();
        taskItemRepository = repositoryEngine.getTaskItemRepository();
        loggerRepository = repositoryEngine.getLoggerRepository();
        jobRepository = repositoryEngine.getJobRepository();
    }

    public List<TaskEntity> findTaskEntity(TaskQuery query) {
        return taskRepository.findTaskEntity(query);
    }

    public Map<String, Object> queryTaskRunDetails(String taskId) {
        Map<String, Object> taskRunDetail = new HashMap<String, Object>();
        TaskEntity task = taskRepository.getTaskEntityById(taskId);
        taskRunDetail.put("task", task);
        List<TaskItemEntity> taskItems = taskItemRepository.getTaskItemByTaskId(taskId);
        taskRunDetail.put("taskItems", taskItems);
        List<TaskTrackerEntity> taskTrackers = taskTrackerRepository.findTaskTrackerByTask(task.getTaskGroup(),
            task.getTaskName());
        taskRunDetail.put("taskTrackers", taskTrackers);
        return taskRunDetail;
    }

    public List<TaskTrackerEntity> queryTaskTrackers(TaskTrackerQuery query) {
        return taskTrackerRepository.findTaskTrackerPage(query);
    }

    public TaskEntity getTaskById(String taskId) {
        return taskRepository.getTaskEntityById(taskId);
    }

    public String saveTask(TaskEntity task) {
        try {
            List<TaskItemEntity> taskItems = new ArrayList<TaskItemEntity>();
            if (null != task) {
                if (StringUtils.isBlank(task.getTaskItem())) {
                    if (!StringUtils.isBlank(task.getRunStartTime())) {
                        taskItems.add(new TaskItemEntity(task.getTaskId(),
                            "",
                            task.isImmediatelyRun() ? 0 : DateUtils.getNextValidTimeAfter4Cron(task.getRunStartTime(),
                                Clock.getCurrentDate()), task.isAutoRecovery()));
                    } else {
                        taskItems.add(new TaskItemEntity(task.getTaskId(), "", task.isAutoRecovery()));
                    }
                } else {
                    Collection<String> params = StringUtils.getTrimmedStringCollection(task.getTaskItem());
                    if (!StringUtils.isBlank(task.getRunStartTime())) {
                        for (String param : params) {
                            if (!StringUtils.isBlank(param)) {
                                taskItems.add(new TaskItemEntity(task.getTaskId(),
                                    param,
                                    task.isImmediatelyRun() ? 0 : DateUtils.getNextValidTimeAfter4Cron(task.getRunStartTime(),
                                        Clock.getCurrentDate()),
                                    task.isAutoRecovery()));
                            }
                        }
                    } else {
                        for (String param : params) {
                            if (!StringUtils.isBlank(param)) {
                                taskItems.add(new TaskItemEntity(task.getTaskId(), param, task.isAutoRecovery()));
                            }
                        }
                    }
                }
            }
            taskItemRepository.removeTaskItemByTaskId(task.getTaskId().getTaskId());
            taskItemRepository.saveTaskItem(taskItems);
            taskRepository.saveTaskEntity(task);
        } catch (Throwable e) {
            logger.error("Save task and taskItem failure, Delete all taskItems. task id is : "
                         + task.getTaskId().getTaskId(), e);
            taskItemRepository.removeTaskItemByTaskId(task.getTaskId().getTaskId());
            return e.getMessage();
        }
        return null;
    }

    public void updateTaskStatus(String taskId, TaskStatus status) {
        taskRepository.updateTaskStatus(taskId, status);
    }

    @Override
    public long findRunningTaskItemNumByTaskId(String taskId) {
        return taskItemRepository.findRunningTaskItemNumByTaskId(taskId);
    }

    public List<JobEntity> queryAllJob(JobQuery job) {
        return jobRepository.queryAllJobs();
    }

    public void saveJob(JobEntity job, List<String> taskIds) throws ParseException {
        boolean isUpdate = false;
        if (job.getJobId() == null) {
            job.setJobId(new JobID(DateUtils.format(Clock.getCurrentDate(), DateUtils.YYYYMMDDHHMMSS)));
        } else {
            isUpdate = true;
            taskRepository.delJobIdForTask(job.getJobId());
        }
        if (job.getJobStatus() == null) {
            job.setJobStatus(JobStatus.INIT);
        }
        if (job.getCreateTime() == 0) {
            job.setCreateTime(Clock.getSystemTime());
        }
        taskItemRepository.updateNextRunTime(job.getJobId(),
            taskIds,
            job.isImmediatelyRun() ? Clock.getSystemTime() : DateUtils.getNextValidTimeAfter4Cron(job.getRunStartTime(),
                Clock.getCurrentDate()));
        taskRepository.saveJobIdForTask(job, taskIds);
        jobRepository.saveJob(job);
        logger(job, taskIds, isUpdate);
    }

    @Override
    public void startJob(JobID jobId) {
        jobRepository.updateJobStatus(jobId, JobStatus.START);
        taskRepository.updateTaskStatus(jobId, TaskStatus.START);
        logger(jobId, LogType.START_JOB);
    }

    @Override
    public void stopJob(JobID jobId) {
        taskRepository.updateTaskStatus(jobId, TaskStatus.STOP);
        jobRepository.updateJobStatus(jobId, JobStatus.STOP);
        logger(jobId, LogType.STOP_JOB);
    }

    @Override
    public void delJob(JobID jobId) {
        taskRepository.delJobIdForTask(jobId);
        jobRepository.removeJob(jobId);
        logger(jobId, LogType.DELETE_JOB);

    }

    public JobEntity queryJobById(String jobId) {
        return jobRepository.queryJobById(jobId);
    }

    public List<TaskEntity> queryTasksNotRelatedJob() {
        return taskRepository.queryTasksNotRelatedJob();
    }

    public List<TaskEntity> queryTasksRelatedJob(JobID jobId) {
        return taskRepository.queryTasksRelatedJob(jobId);
    }

    @Override
    public long findRunningTaskItemNumByJobId(JobID jobId) {
        List<String> taskIds = taskRepository.queryAllTaskIDByJobId(jobId);
        return taskItemRepository.findRunningTaskItemNumByJobId(taskIds);
    }

    @Override
    public Page queryTaskTrackerLog(String taskTrackerUuid, long startTime, long endTime, int page, int rows) {
        return loggerRepository.queryTaskTrackerLog(taskTrackerUuid, startTime, endTime, page, rows);
    }

    @Override
    public Page queryJobLog(UserLogQuery userLogQuery, int page, int rows) {
        return loggerRepository.queryJobLog(userLogQuery.getJobId(), userLogQuery.getStartTime(), userLogQuery.getEndTime(), page, rows);
    }

    @Override
    public Page queryTaskTrackerDisconnectLog(String ip, long startDate, long endDate, int page, int rows) {
        return loggerRepository.queryTaskTrackerDisconnectLog(ip, startDate, endDate, page, rows);
    }

    @Override
    public Page queryTaskExeFailureLog(String jobId, String taskId, long startDate, long endDate, int page, int rows) {
        return loggerRepository.queryTaskExeFailureLog(jobId, taskId, startDate, endDate, page, rows);
    }

    @Override
    public Page queryTaskLog(LogQuery query) {
        return loggerRepository.queryTaskLog(query.getJobId(),
            query.getTaskId(),
            query.getStartTime(),
            query.getEndTime(),
            query.getOffset(),
            query.getLimit());
    }

    @Override
    public Page queryTaskRunRecord(String jobId, String taskId, long startDate, long endDate, int page, int rows) {
        return null;
    }

    @Override
    public List<TaskItemEntity> queryTaskItemsByTimeout(TaskItemQuery query) {
        return null;
    }

    @Override
    public void recoveryTaskItemByIds(long timeout, String[] ids) {

    }

    @Override
    public List<TaskItemEntity> queryTaskItemsForLongtime(TaskItemQuery query) {
        return null;
    }

    @Override
    public void removeTaskTrackerAndTaskDefines(String taskTrackerUuid) {
        
    }

    @Override public boolean hasTaskItem(String taskId) {
        return true;
    }

    @Override public Page queryUserPage(UserQuery query, int page, int rows) {
        return null;
    }

    @Override public UserEntity queryUserByUsername(String username) {
        return null;
    }

    @Override public void updateUserPws(String username, String password) {

    }

    @Override public UserEntity findByUsernameAndPassword(String username, String password) {
        return null;
    }

    @Override public void updateUser(UserEntity user) {

    }

    @Override public void saveUser(UserEntity user) {

    }
}
